package com.bzkj.document.utils.common;

import com.bzkj.document.domain.DocumentNoCounter;
import com.bzkj.document.mapper.DocumentNoMapper;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @projectName: bzkj-wms
 * @package: com.bzkj.common.utils
 * @className: DocumentNoUtils
 * @description: 单据号生成工具类
 * @author: C1309
 * @createDate: 2024年11月21日
 * @version: v1.0
 */
@Component
public class DocumentNoUtils {

    @Resource
    private DocumentNoMapper counterRepository;
    /***
     * 保存当天的日期（用于重置计数器）
     */
    private static String currentDate = getCurrentDate();

    /**
     * 保存每种单据类型的当前日期
     */
    private final Map<String, String> currentDateMap = new ConcurrentHashMap<>();

    /**
     * 初始化方法，在启动时执行
     */
    @PostConstruct
    public void initializeCurrentDateMap() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
        // 从数据库加载所有单据类型
        List<HashMap<String, Object>> allDocumentTypes = counterRepository.getAllDocumentTypes();
        for (int i = 0; i < allDocumentTypes.size(); i++) {
            HashMap<String, Object> counterMap = allDocumentTypes.get(i);
            String type = (String) counterMap.get("type");
            // 初始化当前日期
            Date currentDate = (Date) counterMap.get("currentDate");
            currentDateMap.put(type, sdf.format(currentDate));
        }

    }

    /**
     * 从数据库中加载对应类型的计数器值
     *
     * @param type 类型
     * @return 结果
     */
    private int getCurrentCounterValue(String type) {
        // 从数据库加载当前计数器值
        DocumentNoCounter counter = counterRepository.getDocumentNoByType(type);
        return counter.getCurrentValue();
    }

    /**
     * 更新数据库中对应类型的计数器值
     *
     * @param type 类型
     */
    private void setCounterValue(String type, int newValue) {
        DocumentNoCounter counter = new DocumentNoCounter(type, newValue);
        // 更新数据库中的计数器值
        counterRepository.updateDocumentNo(counter);
    }

    /**
     * 获取当前日期，格式为 yyMMdd
     *
     * @return 当前日期字符串
     */
    private static String getCurrentDate() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
        return sdf.format(new Date());
    }

    /**
     * 生成单据号
     *
     * @param type    单据类型
     * @param today   当前日期
     * @param counter 流水号
     * @return 生成的单据号
     */
    private String generateOrderNumber(String type, String today, int counter) {
        String countPart = String.format("%05d", counter);
        return type + today + countPart;
    }

    /**
     * 生成采购入库单号
     * 格式：PIyyMMddNNNNN
     *
     * @return 生成的采购入库单号
     */
    @Transactional(rollbackFor = Exception.class)
    public synchronized String generatePiOrderNumber() {

        String today = getCurrentDate();
        // 如果日期发生变化，重置计数器
        if (!today.equals(currentDateMap.get("PIN"))) {
            currentDate = today;
            currentDateMap.put("PIN", today);
            setCounterValue("PIN", 1);
        }
        // 获取递增编号
        int currentPiCounter = getCurrentCounterValue("PIN");

        // 生成单号
        String orderNumber = generateOrderNumber("PIN", today, currentPiCounter);

        // 更新计数器
        setCounterValue("PIN", currentPiCounter + 1);

        return orderNumber;
    }

    /**
     * 生成产成品入库单据号
     * 格式：PRTyyMMddNNNNN
     *
     * @return 生成的产成品入库单据号
     */
    @Transactional(rollbackFor = Exception.class)
    public synchronized String generatePrtOrderNumber() {
        String today = getCurrentDate();
        // 如果日期发生变化，重置计数器
        if (!today.equals(currentDateMap.get("PRT"))) {
            currentDate = today;
            currentDateMap.put("PRT", today);
            setCounterValue("PRT", 1);
        }
        // 获取递增编号
        int currentPiCounter = getCurrentCounterValue("PRT");

        // 生成单号
        String orderNumber = generateOrderNumber("PRT", today, currentPiCounter);

        // 更新计数器
        setCounterValue("PRT", currentPiCounter + 1);

        return orderNumber;
    }

    /**
     * 生成退货入库单据号
     * 格式：PRTyyMMddNNNNN
     *
     * @return 生成的退货入库单据号
     */
    @Transactional(rollbackFor = Exception.class)
    public synchronized String generateRtiOrderNumber() {
        String today = getCurrentDate();
        // 如果日期发生变化，重置计数器
        if (!today.equals(currentDateMap.get("RTI"))) {
            currentDate = today;
            currentDateMap.put("RTI", today);
            setCounterValue("RTI", 1);
        }
        // 获取递增编号
        int currentPiCounter = getCurrentCounterValue("RTI");

        // 生成单号
        String orderNumber = generateOrderNumber("RTI", today, currentPiCounter);

        // 更新计数器
        setCounterValue("RTI", currentPiCounter + 1);

        return orderNumber;
    }

    /**
     * 生成其他入库单据号
     * 格式：PRTyyMMddNNNNN
     *
     * @return 生成的其他入库单据号
     */
    @Transactional(rollbackFor = Exception.class)
    public synchronized String generateOitOrderNumber() {
        String today = getCurrentDate();
        // 如果日期发生变化，重置计数器
        if (!today.equals(currentDateMap.get("OIT"))) {
            currentDate = today;
            currentDateMap.put("OIT", today);
            setCounterValue("OIT", 1);
        }
        // 获取递增编号
        int currentPiCounter = getCurrentCounterValue("OIT");

        // 生成单号
        String orderNumber = generateOrderNumber("OIT", today, currentPiCounter);

        // 更新计数器
        setCounterValue("OIT", currentPiCounter + 1);

        return orderNumber;
    }


    /**
     * 生成销售出库单据号
     * 格式：SOyyMMddNNNNN
     *
     * @return 生成的销售单据号
     */
    @Transactional(rollbackFor = Exception.class)
    public synchronized String generateSalOrderNumber() {
        String today = getCurrentDate();
        // 如果日期发生变化，重置计数器
        if (!today.equals(currentDateMap.get("SAL"))) {
            currentDate = today;
            currentDateMap.put("SAL", today);
            setCounterValue("SAL", 1);
        }
        // 获取递增编号
        int currentPiCounter = getCurrentCounterValue("SAL");

        // 生成单号
        String orderNumber = generateOrderNumber("SAL", today, currentPiCounter);

        // 更新计数器
        setCounterValue("SAL", currentPiCounter + 1);

        return orderNumber;
    }

    /**
     * 生成材料出库单据号
     * 格式：MTAyyMMddNNNNN
     *
     * @return 生成的销售单据号
     */
    @Transactional(rollbackFor = Exception.class)
    public synchronized String generateMatOrderNumber() {
        String today = getCurrentDate();
        // 如果日期发生变化，重置计数器
        if (!today.equals(currentDateMap.get("MAT"))) {
            currentDate = today;
            currentDateMap.put("MAT", today);
            setCounterValue("MAT", 1);
        }
        // 获取递增编号
        int currentPiCounter = getCurrentCounterValue("MAT");

        // 生成单号
        String orderNumber = generateOrderNumber("MAT", today, currentPiCounter);

        // 更新计数器
        setCounterValue("MAT", currentPiCounter + 1);

        return orderNumber;
    }

    /**
     * 转库单单据号
     * 格式：TRFyyMMddNNNNN
     *
     * @return 转库单
     */
    @Transactional(rollbackFor = Exception.class)
    public synchronized String generateTrfOrderNumber() {
        String today = getCurrentDate();
        // 如果日期发生变化，重置计数器
        if (!today.equals(currentDateMap.get("TRF"))) {
            currentDate = today;
            currentDateMap.put("TRF", today);
            setCounterValue("TRF", 1);
        }
        // 获取递增编号
        int currentPiCounter = getCurrentCounterValue("TRF");

        // 生成单号
        String orderNumber = generateOrderNumber("TRF", today, currentPiCounter);

        // 更新计数器
        setCounterValue("TRF", currentPiCounter + 1);

        return orderNumber;
    }

    /**
     * 生成退货出库单据号
     * 格式：RTNyyMMddNNNNN
     *
     * @return 生成的销售单据号
     */
    @Transactional(rollbackFor = Exception.class)
    public synchronized String generateRtnOrderNumber() {
        String today = getCurrentDate();
        // 如果日期发生变化，重置计数器
        if (!today.equals(currentDateMap.get("RTN"))) {
            currentDate = today;
            currentDateMap.put("RTN", today);
            setCounterValue("RTN", 1);
        }
        // 获取递增编号
        int currentPiCounter = getCurrentCounterValue("RTN");

        // 生成单号
        String orderNumber = generateOrderNumber("RTN", today, currentPiCounter);

        // 更新计数器
        setCounterValue("RTN", currentPiCounter + 1);

        return orderNumber;
    }

    /**
     * 生成其他出库单据号
     * 格式：OTHyyMMddNNNNN
     *
     * @return 生成的销售单据号
     */
    @Transactional(rollbackFor = Exception.class)
    public synchronized String generateOthOrderNumber() {
        String today = getCurrentDate();
        // 如果日期发生变化，重置计数器
        if (!today.equals(currentDateMap.get("OTH"))) {
            currentDate = today;
            currentDateMap.put("OTH", today);
            setCounterValue("OTH", 1);
        }
        // 获取递增编号
        int currentPiCounter = getCurrentCounterValue("OTH");

        // 生成单号
        String orderNumber = generateOrderNumber("OTH", today, currentPiCounter);

        // 更新计数器
        setCounterValue("OTH", currentPiCounter + 1);

        return orderNumber;
    }

    /**
     * 生成其他出库单据号
     * 格式：OTHyyMMddNNNNN
     *
     * @return 生成的销售单据号
     */
    @Transactional(rollbackFor = Exception.class)
    public synchronized String generateStOrderNumber() {
        String today = getCurrentDate();
        // 如果日期发生变化，重置计数器
        if (!today.equals(currentDateMap.get("STO"))) {
            currentDate = today;
            currentDateMap.put("STO", today);
            setCounterValue("STO", 1);
        }
        // 获取递增编号
        int currentPiCounter = getCurrentCounterValue("STO");

        // 生成单号
        String orderNumber = generateOrderNumber("STO", today, currentPiCounter);

        // 更新计数器
        setCounterValue("STO", currentPiCounter + 1);

        return orderNumber;
    }


}
